﻿﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions; 

namespace Tools.Web
{
    /// <summary>
    /// 过滤危险的HMTL标记，只保留安全的
    /// </summary>
    public class HtmlFilter
    {
        private static Regex tagExpression = new Regex(@"<(?<slash>/?)\s*?(?<tag>\w+)\s?(?<attr>[^>]*?)(?<close>/>|>|$)");
        private static Regex attrExpression = new Regex(@"(?<attr>\S*?)=(?<val>(""[^""]*"")|('[^']*')|(\S*))");
        private static Regex stripExpression = new Regex(@"<[^>]*>");
        private static Regex cleanUrlExpression = new Regex(@"[?&:<>*/ ]+");

        /// <summary>
        /// 危险的标记
        /// </summary>
        private static string[] SafeTags { get; set; }

        /// <summary>
        /// 危险的属性
        /// </summary>
        private static string[] SafeAttributes { get; set; }

        static HtmlFilter()
        {
            SafeTags = new string[]{
			                       	"b", "del", "i", "ins", "u", "font", "big", "small", "sub", 
			                       	"sup", "h1", "h2", "h3", "h4", "h5", "h6", "cite", "code", 
			                       	"em", "s", "strike", "strong", "tt", "var", "div", "center", 
			                       	"blockquote", "ol", "ul", "dl", "table", "caption", "pre", 
			                       	"ruby", "rt", "rb", "rp", "p", "span", "u", "br", "hr", "li", 
			                       	"dt", "dd", "td", "th", "tr", "a", "img"
			                       };
            SafeAttributes = new string[]{
			                             	"href", "title", "target", "rel", "src", "alt", "align" ,"color"
			                             };
        }
        
        /// <summary>
        /// 剥夺HTML代码，不保留任何HTML
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public virtual string StripHtml(string html)
        {
            return stripExpression.Replace(html, string.Empty);
        }

        /// <summary>
        /// 去掉连接
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public virtual string CleanUrl(string text)
        {
            return cleanUrlExpression.Replace(StripHtml(text), "-");
        }

        /// <summary>
        /// 过滤HTML标记
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public virtual string FilterHtml(string html)
        {
            return tagExpression.Replace(html, FilterDangerousTags);
        }

        /// <summary>
        /// 过滤危险的HTML标记
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        protected virtual string FilterDangerousTags(Match match)
        {
            string tag = match.Groups["tag"].Value.ToLower();
            bool isSafe = Array.IndexOf(SafeTags, tag) >= 0;
            if (!isSafe)
                return string.Empty;
            return FilterDangerousAttributes(match, tag);
        }

        /// <summary>
        /// 过滤危险的属性
        /// </summary>
        /// <param name="match"></param>
        /// <param name="tag"></param>
        /// <returns></returns>
        protected virtual string FilterDangerousAttributes(Match match, string tag)
        {
            string slash = match.Groups["slash"].Value;
            string attributesPortion = match.Groups["attr"].Value;
            string filteredAttributes = string.Empty;
            foreach (Match attrMatch in attrExpression.Matches(attributesPortion))
            {
                string attr = attrMatch.Groups["attr"].Value.ToLower();
                if (Array.IndexOf(SafeAttributes, attr) >= 0)
                {
                    string value = attrMatch.Groups["val"].Value;
                    filteredAttributes += " " + attr + "=" + value;
                }
            }
            string close = match.Groups["close"].Value;
            return "<" + slash + tag + filteredAttributes + close;
        }
    }
}
